import {
  Conversations,
  ConversationsProps,
  Prompts,
  Sender,
  useXAgent,
  useXChat,
  Welcome,
} from '@ant-design/x';

import {createStyles} from 'antd-style';
import React, {useEffect} from 'react';
import {
  DeleteOutlined,
  FireOutlined,
  HeartOutlined,
  PaperClipOutlined,
  PlusOutlined,
  ReadOutlined,
  SmileOutlined,
} from '@ant-design/icons';
import {Badge, Button, type GetProp, message as antdMessage, Space, UploadFile} from 'antd';

import {difyHttpRedirect, openLoginModal, reqHost} from "./componments/ComReq";
import LoginModal from "./componments/logins/LoginModal";
import {getUserInfoFromLocal, getUserTokenFromLocal} from "./componments/utils/LocalStorageUtils";
import {MessageInfo} from "@ant-design/x/es/useXChat";
import {PromptProps} from "@ant-design/x/es/prompts";
import {BubbleContent, FileContent, OpType, RedirectDifyReq} from "./componments/types/CommonTypes";
import AliyunOSSUpload from "./componments/upload/AliOssUpload";
import RundelBubble from "./componments/bubble/RundelBubble";
import {startRecording, stopRecording} from "./componments/audio/AudioRecognitionV2";

// // 渲染标题的辅助函数
const renderTitle = (icon: React.ReactElement, title: string) => (
    <Space align="start">
      {icon}
      <span>{title}</span>
    </Space>
);

// 样式定义
const useStyle = createStyles(({token, css}) => {
  return {
    layout: css`
      width: 100%;
      min-width: 1000px;
      height: 100%;
      border-radius: ${token.borderRadius}px;
      display: flex;
      background: ${token.colorBgContainer};
      font-family: AlibabaPuHuiTi, ${token.fontFamily}, sans-serif;

      .ant-prompts {
        color: ${token.colorText};
      }
    `,
    menu: css`
      background: ${token.colorBgLayout}80;
      width: 280px;
      height: 100%;
      display: flex;
      flex-direction: column;
    `,
    conversations: css`
      padding: 0 12px;
      flex: 1;
      overflow-y: auto;
    `,
    chat: css`
      height: auto;
      width: 100%;
      max-width: 70%;
      margin: 0 auto;
      box-sizing: border-box;
      display: flex;
      flex-direction: column;
      padding: ${token.paddingLG}px;
      gap: 16px;
    `,
    sender: css`
      box-shadow: ${token.boxShadow};
      height: auto;
    `,
    logo: css`
      display: flex;
      height: 72px;
      align-items: center;
      justify-content: start;
      padding: 0 24px;
      box-sizing: border-box;

      img {
        width: 24px;
        height: 24px;
        display: inline-block;
      }

      span {
        display: inline-block;
        margin: 0 8px;
        font-weight: bold;
        color: ${token.colorText};
        font-size: 16px;
      }
    `,
    addBtn: css`
      background: #1677ff0f;
      border: 1px solid #1677ff34;
      width: calc(100% - 24px);
      margin: 0 12px 24px 12px;
    `,
  };
});

// 占位符提示项
const placeholderPromptsItems: GetProp<typeof Prompts, 'items'> = [
  {
    key: '1',
    label: renderTitle(<FireOutlined style={{color: '#FF4D4F'}}/>, '劳动合同纠纷'),
    description: '您需要劳动合同纠纷?',
    children: [
      {
        key: '1-1',
        description: `什么是劳动合同纠纷`,
      },
      {
        key: '1-2',
        description: `工伤等级认定和伤残等级认定的区别`,
      }
    ],
  },
  {
    key: '2',
    label: renderTitle(<ReadOutlined style={{color: '#1890FF'}}/>, '法律咨询'),
    description: '您有法律相关问题都可以问我',
    children: [
      {
        key: '2-1',
        icon: <HeartOutlined/>,
        description: `发生交通事故不报案，现场协商了，后来对方不认可了怎么办`,
      },
      {
        key: '2-2',
        icon: <SmileOutlined/>,
        description: `劳动合同和劳务合同的区别`,
      }
    ],
  },
  {
    key: '3',
    label: renderTitle(<FireOutlined style={{color: '#FF4D4F'}}/>, '法律检索'),
    description: '快速检索法律条款内容',
    children: [
      {
        key: '1-1',
        description: `中华人民共和国宪法第4章第一款`,
      },
      {
        key: '1-2',
        description: `中华人民共和国刑法一共多少条`,
      }
    ],
  },

];
const Independent: React.FC = () => {
  // ==================== 样式 ====================
  const {styles} = useStyle();
  // ==================== 状态 ====================
  const [headerOpen, setHeaderOpen] = React.useState(false);
  const [content, setContent] = React.useState('');
  const [conversationsItems, setConversationsItems] = React.useState<{ label: string; key: string }[]>([],);
  const [showLoginModal, setShowLoginModal] = React.useState(false);
  const [currMessageId, setCurrMessageId] = React.useState("");
  const [recording, setRecording] = React.useState(false);
  // 发送提示项
  const [senderPromptsItems, setSenderPromptsItems] = React.useState<PromptProps[]>([]);

  const audioCurrTxtRef = React.useRef<string>('');
  const audioTxtArrRef = React.useRef<string[]>([]);
  const conversationIdRef = React.useRef("");
  const currPageLastConversationIdRef = React.useRef("");
  const pageConversationLastRef = React.useRef(false);
  const conversationLoadingRef = React.useRef(false);
  const currFilePathRef = React.useRef("");
  const currOrgFilePathRef = React.useRef("");
  const currMessageIdRef = React.useRef("");
  const currTaskIdRef = React.useRef("");
  const msgIdMappingRef = React.useRef<Record<string, string>>({});
  // ==================== 运行时逻辑 ====================
  const [agent] = useXAgent({
    request: async ({ message }, { onSuccess, onUpdate, onError }) => {
      if (message) {
        try {
          /*const style = document.createElement('style');
          style.innerHTML = `
              .ant-bubble.css-dev-only-do-not-override-7qjh75.ant-bubble-start {
                display: flex !important;
              }
              :where(.css-7qjh75).ant-bubble {
                display: flex !important;
              }`;
          document.head.appendChild(style);*/
          // document.head.removeChild(style);
          // 使用 fetch 实现 curl 请求
          const userInfo = getUserInfoFromLocal();
          if (!userInfo) {
            setShowLoginModal(true);
            return
          }
          const reqData = {
            url:"chat-messages",
            fileResourceIdList:[currFilePathRef.current],
            body :{
              "inputs": {},
              "query": message,
              "conversation_id": conversationIdRef.current,
              "response_mode": "streaming",
              "files": [],
              "parent_message_id":currMessageIdRef.current
            }
          }
          const chatResponse = await fetch(reqHost+ '/unifiedApi/ai/stream', {
            method: 'POST',
            headers: {
              "rToken":getUserTokenFromLocal()||"",
              "Content-Type": "application/json",
            },
            body: JSON.stringify(reqData)
          });
          if(chatResponse.status == 401) {
            setShowLoginModal(true);
            return;
          }
          // 检查响应状态是否成功
          if (!chatResponse.ok) {
            throw new Error(`HTTP error! status: ${chatResponse.status}`);
          }
          // 处理流式响应
          // 确保 chatResponse.body 不为 null
          if (!chatResponse.body) {
            throw new Error('No response body available');
          }
          const reader = chatResponse.body.getReader();
          const decoder = new TextDecoder();
          let message2='<summary style="animation: flash 1s infinite;"> 正在思考中... </summary>';
          onUpdate(message2);
          //标记是否已开始加载
          let loadStarted = false;
          while (true) {
            const { done, value } = await reader.read();
            if (done) break;
            // 解码当前数据块
            const chunk = decoder.decode(value, { stream: true });
            const lines=chunk.split('\n\n');
            //let isEnd = false;
            for (const line of lines) {
              if (line==="") {
                continue;
              }
              const jsonStr = line.replace("data:", "").trim(); // 移除 "data: " 前缀
              try {
                // debugger;
                if (jsonStr!="") {
                  const jsonObject = JSON.parse(jsonStr)? JSON.parse(jsonStr) :''; // 解析 JSON 字符串
                  if (jsonObject.event==="req_accepted") {
                    message2='<summary style="animation: flash 1s infinite;"> 正在思考中...</summary>';
                    onUpdate(message2);
                    continue;
                  }
                  if (jsonObject.event==="file_parsing") {
                    message2='<summary style="animation: flash 1s infinite;"> 正在解读文件...</summary>';
                    onUpdate(message2);
                    continue;
                  }
                  if (jsonObject.answer){
                    if (!loadStarted){
                      message2='';
                      loadStarted = true;
                      currMessageIdRef.current = jsonObject.message_id;
                      conversationIdRef.current = jsonObject.conversation_id;
                      setCurrMessageId(jsonObject.message_id);
                    }
                    message2 +=jsonObject.answer;
                    currTaskIdRef.current = jsonObject.task_id;
                    onUpdate(message2);
                  }
                  if (jsonObject.event==="message_end") {
                    currFilePathRef.current = "";
                    currOrgFilePathRef.current = "";
                    querySuggestedMsg();
                    currPageLastConversationIdRef.current="";
                    queryConversations(true);
                  }
                }
              } catch (error) {
                console.error("Failed to parse JSON:", error);
              }
            }
          }
          onSuccess(message2);
        } catch (error) {
          antdMessage.error('大模型 API 错误');
          console.error('大模型 API 错误:', error);
          onError(error as Error);
        }
      }
    }
  });

  const {onRequest, messages, setMessages} = useXChat({agent});

  const queryConversations = (mustRefresh: boolean|false)=>{
    if (!mustRefresh && (pageConversationLastRef.current || conversationLoadingRef.current)) {
      console.log("queryConversations", pageConversationLastRef.current, conversationLoadingRef.current);
      return;
    }
    conversationLoadingRef.current = true;
    const userTokenFromLocal = getUserTokenFromLocal();
    if (userTokenFromLocal) {
      const difyReq: RedirectDifyReq = {
        difyUrl: "conversations",
        method: "GET",
        difyReqParam: {
          limit: 20,
          last_id: currPageLastConversationIdRef.current
        },
        defaultResDataField:"result"
      }
      difyHttpRedirect(difyReq)
          .then((result)=>{
            const res = result as Record<string, []>;
            const data = res?.data;
            if (!data || data.length <= 0) {
              pageConversationLastRef.current = true;
              return;
            } else pageConversationLastRef.current = data.length < 20;
            const thisItems: { key: string; label: string; }[] = [];
            data.forEach((d: { id: string; name: string; }) => {
              currPageLastConversationIdRef.current = d.id;
              if (!mustRefresh) {
                setConversationsItems(sourceItems=>[...sourceItems, {key: d.id, label: d.name}]);
              } else {
                thisItems.push({key: d.id, label: d.name});
              }
            });
            if (mustRefresh) {
              setConversationsItems(thisItems);
            }
          })
          .catch(err=>{
            if (err===openLoginModal) {
              //打开登陆框
              setShowLoginModal(true);
            } else {
              antdMessage.error(err);
            }
          }).finally(()=>{
        conversationLoadingRef.current=false;
      });
    }
  }

  const querySuggestedMsg=()=>{
    if (!currMessageIdRef.current || currMessageIdRef.current==="") {
      return;
    }
    const userTokenFromLocal = getUserTokenFromLocal();
    if (userTokenFromLocal) {
      const difyReq: RedirectDifyReq = {
        difyUrl: "/messages/" + currMessageIdRef.current + "/suggested",
        method: "GET",
        difyReqParam: {},
        defaultResDataField:"result"
      }
      difyHttpRedirect(difyReq)
          .then((result)=>{
            const res = result as Record<string, []>;
            const suggestedMsg = res?.data;
            const suggestedPrompts = [];
            for (let i = 0; i < suggestedMsg?.length; i++) {
              suggestedPrompts.push({
                key: suggestedMsg[i],
                description: suggestedMsg[i],
                label: suggestedMsg[i],
                icon: <FireOutlined style={{color: '#FF4D4F'}}/>,
              });
            }
            setSenderPromptsItems(suggestedPrompts);
          })
          .catch(err=>{
            if (err===openLoginModal) {
              //打开登陆框
              setShowLoginModal(true);
            } else {
              antdMessage.error(err);
            }
          });
    }
  }
  useEffect(() => {
    // ===============会话列表=====================
    queryConversations(true);
    //querySuggestedMsg();
  }, [currMessageId,setMessages]);

  const onSubmit = (nextContent: string) => {
    if (!loginCheck()) {
      return;
    }
    if (!nextContent) return;
    onRequest(nextContent);
    setContent('');
    setHeaderOpen(false);
    audioTxtArrRef.current = [];
    audioCurrTxtRef.current='';
  };
  const submitStop = ()=>{
    if (!currTaskIdRef.current){
      antdMessage.info("无需暂停");
      return;
    }
    const difyReq: RedirectDifyReq = {
      difyUrl: "/chat-messages/" + currTaskIdRef.current + "/stop",
      method: "POST",
      difyReqParam: {},
      defaultResDataField:"result"
    }
    difyHttpRedirect(difyReq)
        .then(()=>{
          //const res = result as Record<string, []>;
          antdMessage.info("取消成功");
        })
        .catch(err=>{
          if (err===openLoginModal) {
            //打开登陆框
            setShowLoginModal(true);
          } else {
            antdMessage.error(err);
          }
        });
  }

  const onPromptsItemClick: GetProp<typeof Prompts, 'onItemClick'> = (info) => {
    if (!loginCheck()) {
      return;
    }
    onRequest(info.data.description as string);
  };
  const loginCheck=()=>{
    const userTokenFromLocal = getUserTokenFromLocal();
    if (!userTokenFromLocal) {
      setShowLoginModal(true);
      return false;
    }
    return true;
  }
  //打开新回话
  const onAddConversation = () => {
    if (!loginCheck()) {
      return;
    }
    setMessages([]);
    currMessageIdRef.current="";
    conversationIdRef.current="";
    setCurrMessageId("");
  };
  const queryMessageRecord = (conversationId:string)=>{
    conversationIdRef.current = conversationId;
    const difyReq: RedirectDifyReq = {
      difyUrl: "messages",
      method: "GET",
      difyReqParam: {
        conversation_id: conversationId,
        limit: 20,
        first_id: "",
      },
      defaultResDataField:"result"
    }
    difyHttpRedirect(difyReq)
        .then((result)=>{
          const res = result as Record<string, []>;
          const dList = res?.data;
          const items: React.SetStateAction<MessageInfo<string>[]> = [];
          let conversationId = "";
          dList.forEach((d: { id: string; query: string; answer: string; conversation_id:string}) => {
            items.push({id: d.id, message: d.query, status: "local"});
            items.push({id: d.id, message: d.answer, status: "success"});
            if (!conversationId || conversationId===""){
              conversationId = d.conversation_id;
            }
            return;
          });
          setMessages(items);
        })
        .catch(err=>{
          if (err===openLoginModal) {
            //打开登陆框
            setShowLoginModal(true);
          } else {
            antdMessage.error(err);
          }
        });
  }
  //会话点击
  const onConversationClick: GetProp<typeof Conversations, 'onActiveChange'> = (key) => {
    queryMessageRecord(key);
  };

  const handleFileChange=(fileList:UploadFile[]) =>{
    fileList.forEach((file)=>{
      if (file.url != null) {
        currFilePathRef.current = file.url;
        currOrgFilePathRef.current = file.name || file.fileName as string
      }
    });
  }
  // ==================== 节点 ====================
  const placeholderNode = (
          <div style={{
            display: 'grid',
            placeItems: 'center', // 同时实现水平和垂直居中
            height: '70vh', // 设置高度为视口高度
          }}>
            <Space direction="vertical" size={16} style={{paddingTop:"32px"}}>
              <Welcome
                  variant="borderless"
                  icon={<img src="https://pufa-ai.oss-cn-hangzhou.aliyuncs.com/static/deepseek.svg" alt="Deepseek" />}
                  title="Hello,欢迎使用智能法务Ai"
                  description="让我陪您一起解读和学习法律世界"
              />
              <Prompts
                  title="这些我可以帮到你"
                  items={placeholderPromptsItems}
                  styles={{
                    list: {
                      width: '100%',
                    },
                    item: {
                      flex: 1,
                    },
                  }}
                  onItemClick={onPromptsItemClick}
              />
            </Space>
          </div>
      )
  ;
  const promptsItems = senderPromptsItems.map((item)=>{
    return ({
      key: item.key,
      //label: (<b>{item.description}</b>),
      description: item.description,
      icon: <FireOutlined style={{color: '#FF4D4F'}}/>,
    });
  });

  const items = messages.map((e) => {
    const {message, id, status} = e;
    let actualId = msgIdMappingRef.current[id];
    if (!actualId && (typeof e.id === "string" && e.id?.startsWith("msg_")) && status==="success") {
      msgIdMappingRef.current[id]=currMessageIdRef.current;
      actualId = currMessageIdRef.current;
    }
    if (!actualId){
      actualId = id as string;
    }
    let tmpRole = "ai";
    let key = actualId + "_ai";
    const files:FileContent[] = [];
    if (status==="local") {
      tmpRole="local";
      key = actualId+"_local";
      const fileName = currOrgFilePathRef.current;
      if (fileName) {
        files.push({
          name: fileName,
          fileId: fileName,
        });
      }
    }
    const con: BubbleContent = {
      key: key + "_opBtn",
      role: tmpRole,
      msg: message,
      msgId: actualId,
      opTypes: (tmpRole==="ai"?[OpType.dislike,OpType.copy,OpType.read,OpType.like] : []),
      files:files,
    }
    return ({
      key: key,
      role: tmpRole,
      content: con,
    })

  });
  const attachmentsNode = (
      <Badge dot={!headerOpen}>
        {<Button type="text" icon={<PaperClipOutlined/>} onClick={() => setHeaderOpen(!headerOpen)}/>}
      </Badge>
  );

  const senderHeader = (
      <Sender.Header
          title="附件"
          open={headerOpen}
          onOpenChange={setHeaderOpen}
          styles={{
            content: {
              padding: 0,
              width: '100%',
            },
          }}
      >
        <AliyunOSSUpload onChange={handleFileChange}/>
      </Sender.Header>
  );

  const logoNode = (
      <div className={styles.logo}>
        <img
            src="https://pufa-ai.oss-cn-hangzhou.aliyuncs.com/static/react.svg"
            draggable={false}
            alt="logo"
        />
        <span>智能法制</span>
      </div>
  );

  const conversationMenu: ConversationsProps['menu'] = (conversation) => ({
    items: [
      {
        label: '删除',
        key: 'delete',
        icon: <DeleteOutlined />,
      },
    ],
    onClick: () => {
      const difyReq: RedirectDifyReq = {
        difyUrl:"/conversations/" + conversation.key,
        method: "DELETE",
        defaultResDataField:"result",
      }
      difyHttpRedirect(difyReq)
          .then(()=>{
            antdMessage.info("删除成功");
          }).catch(err=>{
            antdMessage.error(err);
      })
    },
  });
  let audioTxtTimer: string | number | NodeJS.Timeout | undefined;
  // ==================== 渲染 ====================
  return (<>
    <LoginModal showLoginModal={showLoginModal} onClose={()=>{
      setShowLoginModal(false);
      queryConversations(true);
    }
    } />
    <div className={styles.layout}>
      <div className={styles.menu}>
        {/*  /!* 🌟 Logo *!/*/}
        {logoNode}
        {/*  /!* 🌟 添加会话 *!/*/}
        <Button
            onClick={onAddConversation}
            type="link"
            className={styles.addBtn}
            icon={<PlusOutlined/>}
        >
          创建新对话
        </Button>

        {/*  /!* 🌟 会话管理 *!/*/}
        <Conversations
            items={conversationsItems}
            className={styles.conversations}
            activeKey={conversationIdRef.current}
            onActiveChange={onConversationClick}
            menu={conversationMenu}
            onScroll={()=>queryConversations(false)}
        />
      </div>
      <div className={styles.chat}>
        {/* 🌟 消息列表 */}
        <RundelBubble defaultNode={[{content: placeholderNode, variant: 'borderless'}]} items={items}/>
        {/* 🌟 提示词 */}
        <Prompts items={promptsItems} onItemClick={onPromptsItemClick}/>
        {/* 🌟 输入框 */}
        <Sender
            value={content}
            header={senderHeader}
            onSubmit={onSubmit}
            onCancel={submitStop}
            onChange={setContent}
            prefix={attachmentsNode}
            loading={agent.isRequesting()}
            placeholder={"有问题您说，努力为您解答，shift+回车换行，回车发送"}
            allowSpeech={{
              // When setting `recording`, the built-in speech recognition feature will be disabled
              recording,
              onRecordingChange: (nextRecording) => {
                if (nextRecording) {
                  startRecording((msg)=>{
                    if (!msg || msg.length<=0) {
                      return;
                    }
                    if (audioCurrTxtRef && msg.length < audioCurrTxtRef.current.length) {
                      audioTxtArrRef.current.push(audioCurrTxtRef.current);
                    }
                    audioCurrTxtRef.current = msg;
                    setContent(msg);
                    let newMsg = "";
                    if (audioTxtArrRef.current && audioTxtArrRef.current.length>0) {
                      audioTxtArrRef.current.forEach(item=>{
                        newMsg = newMsg + item;
                      });
                      setContent(newMsg);
                    }
                    if (audioTxtTimer) {
                      clearTimeout(audioTxtTimer);
                    }
                    audioTxtTimer = setTimeout(()=>{
                      if (audioCurrTxtRef.current && audioCurrTxtRef.current.length>0) {
                        audioTxtArrRef.current.push(audioCurrTxtRef.current);
                      }
                      let newMsg = "";
                      if (audioTxtArrRef.current && audioTxtArrRef.current.length>0) {
                        audioTxtArrRef.current.forEach(item=>{
                          newMsg = newMsg + item;
                        });
                        audioCurrTxtRef.current = '';
                        setContent(newMsg);
                      }
                    }, 2000);
                  }).then(()=>{
                    setRecording(nextRecording);
                    antdMessage.info("您可以开始说话了");
                  }).catch(err=>{
                    if (openLoginModal===err) {
                      setShowLoginModal(true);
                    }
                  });
                } else {
                  antdMessage.info("语音采集结束");
                  stopRecording();
                  setRecording(nextRecording);
                }
              },
            }}
            className={styles.sender}
        />
      </div>
    </div>
  </>);
};

export default Independent;
